package com.arquitectonic.client.datosYlogica;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import com.arquitectonic.client.datosYlogica.vistas.NivelVista;
import com.arquitectonic.client.datosYlogica.vistas.ViewAndBeyond;
import com.arquitectonic.client.datosYlogica.vistas.Vista;
import com.arquitectonic.client.extensiones.Gestor;
import com.arquitectonic.client.extensiones.Par;
import com.arquitectonic.client.servicios.Proxy;
import com.arquitectonic.compartido.Preferencia;
import com.arquitectonic.compartido.Seccion;
import com.arquitectonic.compartido.Sugerencia;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.grid.ListGridRecord;

public class GestorVistas extends Gestor<Vista> {
	
	
	//llamado al setear preferencias por defecto o recargar secciones
	public static void recargarPreferencias(Collection<Preferencia> preferencias) {
		//Elimino preferencias
		for(Vista v: getInstance().getElementos()){
			v.borrarPreferencias();
		}
		// Cargamos los beneficios (preferencias) a las vistas:
		for (Preferencia p:preferencias) {
			Vista v = getInstance().getElemento(p.getNombreVista());
			if (v != null)
				v.agregarPreferencia(p);
		}
	}
	//llamado al setear preferencias por defecto o recargar secciones
	public static void recargarSecciones(Collection<Seccion> secciones) {
		//Elimino secciones
		for(Vista v: getInstance().getElementos()){
			v.borrarSecciones();
		}
		// Cargamos los costos (secciones) a las vistas:
		for (Iterator<Seccion> it = secciones.iterator(); it.hasNext();) {
			Seccion s = it.next();
			Vista v = getInstance().getElemento(s.getNombreVista());
			if (v != null)
				v.agregarSeccion(s);
		}
	}
	
	//llamado al recargar las secciones
	public static void recargarVistas(Collection<Seccion> ses,Collection<Preferencia> prs) {
		
		final LinkedList<Vista> vs = new LinkedList<Vista>();
		
		vs.add(getInstance().getElemento(Seccion.VIEW_AND_BEYOND));
		
		for (Seccion s:ses) {
			if (s.getTipo() == Seccion.INT_VIEW) {
				Vista v=getInstance().getElemento(s.getTitulo());
				if(v==null){
					Vista nuevaVista = new Vista(s.getTitulo());
					nuevaVista.setNivelEnDocumento(s.getNivel());
					vs.add(nuevaVista);
				}else
					vs.add(v);
			}
		}
		
		getInstance().cargarDatos(vs);
		GestorPreferencias.reconstruirListGrid(vs);
		
		recargarPreferencias(prs);
		recargarSecciones(ses);
	}

	// llamados desde GestorLogin:
	static public void cargarVistas(final Collection<Seccion> ses,final Collection<Preferencia> prs,HashMap<String, Integer> tiposVistas) {
		// Construyo las vistas
		final LinkedList<Vista> vs = new LinkedList<Vista>();
		vs.add(new ViewAndBeyond());
		for (Seccion s:ses) {
			if (s.getTipo() == Seccion.INT_VIEW) {
				Vista nuevaVista = new Vista(s.getTitulo());
				nuevaVista.setNivelEnDocumento(s.getNivel());
				vs.add(nuevaVista);
			}
		}
		
		for (Vista v : vs) {
			if (tiposVistas.get(v.getNivelEnDocumento()) != null)
				v.setTipo(tiposVistas.get(v.getNivelEnDocumento()));
		}

		getInstance().cargarDatos(vs);
		GestorPreferencias.reconstruirListGrid(vs);
		
		// Cargamos los costos (secciones) a las vistas:
		for (Iterator<Seccion> it = ses.iterator(); it.hasNext();) {
			Seccion s = it.next();
			Vista v = getInstance().getElemento(s.getNombreVista());
			if (v != null)
				v.agregarSeccion(s);
		}
		// Cargamos los beneficios (preferencias y stakeholders) a las vistas:
		for (Iterator<Preferencia> it = prs.iterator(); it.hasNext();) {
			
			Preferencia p = it.next();
			Vista v = getInstance().getElemento(p.getNombreVista());
			if (v != null)
				v.agregarPreferencia(p);
		}
		
		GestorStakeholders.actualizarSatisfaccionStakeholders();
	}
	
	//DONE
	public static void actualizacionCostoSeccion(Seccion seccion) {
		if (seccion.getNombreVista() != null) {
			Vista v = getInstance().getElemento(seccion.getNombreVista());
			if (v != null)
				getInstance().actualizarElemento(v.getNombreVista(), "costo",v.getCosto());
			
		}
	}
	public static void actualizacionEstadoSeccion(Seccion seccion) {
		if (seccion.getNombreVista() != null) {
			Vista v = getInstance().getElemento(seccion.getNombreVista());
			if (v != null) 
				getInstance().actualizarElemento(v.getNombreVista(), "nivelDeDetalle",v.getNivelDeDetalle());
		}
	}
	
	public static Collection<Sugerencia> getSugerencias() {
		LinkedList<Sugerencia> sugerencias = new LinkedList<Sugerencia>();
		Iterator<Vista> vistas = getInstance().getElementos().iterator();
		while (vistas.hasNext()) {
			vistas.next().enlistarSugerencias(sugerencias);
		}
		return sugerencias;
	}

	public static Collection<Seccion> getSeccionesPriorizadas() {

		// agrego los primeros niveles de cada vista
		SortedSet<NivelVista> aux = new TreeSet<NivelVista>();
		Collection<Vista> vistas = getInstance().getElementos();

		for (Iterator<Vista> it = vistas.iterator(); it.hasNext();) {
			Vista v = it.next();
			for (int nivel = Seccion.INT_OVERVIEW; nivel <= Seccion.INT_DETAILED; nivel++) {
				NivelVista n = v.getNivel(nivel);
				aux.add(n);
			}
		}
		// itero el conjunto para agregar los elementos a la secuencia optima
		List<NivelVista> listaNiveles = new LinkedList<NivelVista>();
		while (!aux.isEmpty()) {
			NivelVista primero = aux.last();
			for (int nivel = Seccion.INT_OVERVIEW; nivel <= primero.getNivel(); nivel++) {
				Vista v = getInstance().getElemento(primero.getNombreVista());
				aux.remove(v.getNivel(nivel));
				listaNiveles.add(v.getNivel(nivel));
			}
		}

		List<Seccion> listaSeccionesOptima = new LinkedList<Seccion>();

		for (Iterator<NivelVista> it = listaNiveles.iterator(); it.hasNext();) {
			NivelVista n = it.next();
			System.out.println("Priorizando:" + n.getNombreVista() + " "
					+ n.getNivel() + " " + n.getCosto() + " "
					+ n.getBeneficio() + " " + n.getCostoPriorizacion() + " "
					+ n.getBeneficioPriorizacion() + " "
					+ n.getCostoBeneficio());

			for (Seccion s: n.getSecciones()){
				if(!listaSeccionesOptima.contains(s))
					listaSeccionesOptima.add(s);
			}
		}

		return listaSeccionesOptima;
	}

	public static void actualizacionPreferencia(Preferencia pref,int anteriorNivelDeseado,int nuevoNivelDeseado) {
		Vista v = getInstance().getElemento(pref.getNombreVista());
		if (v != null) {
			v.actualizarPreferencia(pref,anteriorNivelDeseado, nuevoNivelDeseado);
		}
	}

	// -----------------------------------------

	private static GestorVistas instance = null;

	public static GestorVistas getInstance() {
		if (instance == null)
			instance = new GestorVistas();
		return instance;
	}

	protected GestorVistas() {
		super("Vistas");
	}

	@Override
	protected ListGridRecord toListGridRecord(Vista d) {

		ListGridRecord r = new ListGridRecord();
		r.setAttribute("nombreVista", d.getNombreVista());
		r.setAttribute("costo", d.getCosto());
		r.setAttribute("nivelDeDetalle",
				Seccion.nivelDeDetalleToString(d.getNivelDeDetalle()));
		r.setAttribute("tipo", d.tipoToString());

		return r;
	}
	@Override
	protected Vista toDato(Record r) {
		return null;
	}

	@Override
	public String obtenerClave(Vista dato) {
		return dato.getNombreVista();//o getNivelEnDocumento
	}

	@Override
	protected DataSourceField[] getDataSourceFields() {
		DataSourceTextField nombreVista = new DataSourceTextField(
				"nombreVista", "Nombre");
		nombreVista.setRequired(true);
		nombreVista.setPrimaryKey(true);

		DataSourceTextField costoVista = new DataSourceTextField("costo",
				"Costo");

		DataSourceTextField nivelDeDetalleVista = new DataSourceTextField(
				"nivelDeDetalle", "Nivel de detalle");
		DataSourceTextField tipoVista = new DataSourceTextField(
				"tipo", "Tipo de vista");
		return new DataSourceField[] { nombreVista, costoVista,
				nivelDeDetalleVista,tipoVista };
	}

	@Override
	protected boolean actualizarCampo(Par<Vista, ListGridRecord> dato,
			String campo, Object valor) {

		if (campo.equals("costo")) {
			dato.segundo.setAttribute("costo", ((Integer) valor).toString());
			return true;
		}
		if (campo.equals("nivelDeDetalle")) {
			dato.segundo.setAttribute("nivelDeDetalle",
					Seccion.nivelDeDetalleToString(((Integer) valor)));
			return true;
		}

		if (campo.equals("tipo")) {
			dato.primero.setTipo((Integer) valor);
			dato.segundo.setAttribute("tipo",Vista.tipoToString((Integer) valor));
			return true;
		}

		return false;
	}

	public static void editarTipoVista(String nombreVista, String nuevoTipo) {

				getInstance().actualizarElemento(nombreVista, "tipo", Vista.stringToTipo(nuevoTipo));
				
				Vista ref = getInstance().getElemento(nombreVista);
				
				
				AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {
					@Override
					public void onSuccess(Boolean result) {
		
					}
		
					@Override
					public void onFailure(Throwable caught) {
						SC.warn("Problema persistiendo tipo de una vista.");
					}
				};
		
				Proxy.getServicios().addVista(ref.getNivelEnDocumento(), ref.getTipo(), callback);

	}
	
	public static HashMap<String, String> getTiposVistas() {
		HashMap<String, String> vistas=new HashMap();
		for(Vista v:getInstance().getElementos()){
			vistas.put(v.getNombreVista(),Vista.tipoToString(v.getTipo()));
		}
		
		return vistas;
	}



}
